package com.example.service.impl;

import com.alibaba.fastjson.JSON;
import com.example.Req.LotteryTicketReq;
import com.example.common.BizException;
import com.example.common.Pagination;
import com.example.mapper.LotteryTicketMapper;
import com.example.model.LotteryTicket;
import com.example.model.LotteryTicketRes;
import com.example.model.MongoLotteryTicket;
import com.example.model.NumberRes;
import com.example.model.TicketContent;
import com.example.service.MongoLotteryTicketService;
import com.example.thread.GetBuyTicketTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;

@Service
@Slf4j
public class MongoLotteryTicketServiceImpl implements MongoLotteryTicketService {
    private static Set<String> colorSet = new HashSet<String>() {{
        add("blue");
        add("red");
        add("green");
    }};

    private static Set<String> wuxingSet = new HashSet<String>() {{
        add("金");
        add("木");
        add("水");
        add("火");
        add("土");
    }};

    private static Set<String> animalSet = new HashSet<String>() {{
        add("鼠");
        add("牛");
        add("虎");
        add("兔");
        add("龙");
        add("蛇");
        add("马");
        add("羊");
        add("猴");
        add("鸡");
        add("狗");
        add("猪");
    }};
    @Autowired
    private LotteryTicketMapper lotteryTicketMapper;
    private final String SEPARTOR = ",";
    @Autowired
    private ExecutorService workStealingService;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchInsertLotteryTicket(int year, int type) {
        try {
            String url = "https://kjh.55128.cn/hk6-history-";
            if(type > 2){
                //url = "https://kjh.55128.cn/am6hc-history-";
                url = "https://kjh.55128.cn/newam6hc-history-";
            }
            //URL url = new URL("https://kjh.55128.cn/hk6-history-2022.htm");
            //Document document = Jsoup.parse(url, 100000);
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> result = restTemplate.getForEntity(url + year + ".htm", String.class);
            String str = result.getBody();
            Document document = Jsoup.parse(str);

            Elements element = document.getElementsByTag("body");
            Elements mainElements = element.first().getElementsByClass("main");
            //log.info(mainElements.html());

            Elements div = mainElements.first().getElementsByClass("detail-wrapper");
            Element divTable = document.getElementById("table");
            Element table = divTable.getElementsByTag("table").first();
            // 解析thead标签以及下面的th ,去掉多余的th 标签
            Element theadTr = table.getElementsByTag("thead").first()
                    .getElementsByTag("tr").first();
            Elements theadTrTh = theadTr.getElementsByTag("th");
            theadTrTh.remove(7);
            theadTrTh.remove(6);
            theadTrTh.remove(5);
            theadTrTh.remove(4);
            theadTrTh.remove(3);
            theadTr.empty();
            for (Element th : theadTrTh) {
                theadTr.append(th.toString());
            }
            log.info(theadTr.html());

            Element tbodyElement = table.getElementsByTag("tbody").first();

            // 解析 tbody 标签 以及下面的
            Elements tBodyTrList = table.getElementsByTag("tbody").first()
                    .getElementsByTag("tr");
            List<LotteryTicket> lotteryTickets = new ArrayList<>();
            for (Element tBodyTr : tBodyTrList) {
                Elements tBodyTrTdList = tBodyTr.getElementsByTag("td");
                tBodyTrTdList.remove(8);
                tBodyTrTdList.remove(7);
                tBodyTrTdList.remove(6);
                tBodyTrTdList.remove(5);
                tBodyTrTdList.remove(4);
                tBodyTrTdList.remove(3);
                tBodyTr.empty();
                // 遍历td
                for (Element td : tBodyTrTdList) {
                    log.info(td.html().trim());
                    tBodyTr.append(td.toString());
                }
                // 买🐎 对象
                LotteryTicket lotteryTicket = new LotteryTicket();

                Element dateElement = tBodyTrTdList.get(0); // 开奖日期
                //lotteryTicket.setPublishDate(dateElement.html().trim());

                Element noElement = tBodyTrTdList.get(1);   // 开奖期数
                lotteryTicket.setNo(noElement.html().trim());

                Element numberModuleElement = tBodyTrTdList.get(2);   // 开奖号码模块
                Elements divElementList = numberModuleElement.getElementsByTag("div");

                Element numberDivElement = divElementList.get(0);  // 号码
                Elements numberDivSpanElements = numberDivElement.getElementsByTag("span");
                //List<TicketContent> ticketContents = new ArrayList<>();
                List<String> contentList = new ArrayList<>();
                //List<String> colorList = new ArrayList<>();
                for (Element numberDivSpan : numberDivSpanElements) {
                    /*Set<String> spanClassNames = numberDivSpan.classNames();
                    if (spanClassNames.contains("gray")) {
                        continue;
                    }
                    spanClassNames.retainAll(colorSet);
                    TicketContent ticketContent = new TicketContent();
                    ticketContent.setColor(spanClassNames.iterator().next()); // 颜色
                    ticketContent.setContent(numberDivSpan.html().trim()); //号码

                    contentList.add(ticketContent.getContent());
                    colorList.add(ticketContent.getColor());
                    ticketContents.add(ticketContent);*/

                    String numberStr = numberDivSpan.html().trim();
                    if("+".equals(numberStr)){
                        continue;
                    }
                    int a = Integer.parseInt(numberStr);
                    numberStr = a<10? ("0"+a):(a+"");

                    contentList.add(numberStr);
                }
                //log.info("ticketContents:{}", JSON.toJSONString(ticketContents));
                lotteryTicket.setContent(String.join(SEPARTOR, contentList));
                //lotteryTicket.setColor(String.join(SEPARTOR, colorList));
                lotteryTicket.setType(type);
                //lotteryTicket.setTableIndex(type%2);
                /*Element animalDivElement = divElementList.get(1);  // 生肖
                List<String> animalList = new ArrayList<>();
                Elements animalDivSpanElements = animalDivElement.getElementsByTag("span");
                for (Element animalDivSpan : animalDivSpanElements) {
                    String a = animalDivSpan.html().trim();
                    if (animalSet.contains(a)) {
                        animalList.add(a);
                    }
                }
                log.info("animalList:{}", JSON.toJSONString(animalList));
                lotteryTicket.setAnimalList(animalList);
                lotteryTicket.setAnimal(String.join(SEPARTOR, animalList));

                Element wuxingDivElement = divElementList.get(2);  // 五行
                Elements wuxingDivSpanElements = wuxingDivElement.getElementsByTag("span");
                List<String> wuxingList = new ArrayList<>();
                for (Element wuxingDivSpan : wuxingDivSpanElements) {
                    String a = wuxingDivSpan.html().trim();
                    if (wuxingSet.contains(wuxingDivSpan.html().trim())) {
                        wuxingList.add(a);
                        ;
                    }
                }
                log.info("wuxingList:{}", JSON.toJSONString(wuxingList));
                lotteryTicket.setWuxingList(wuxingList);
                lotteryTicket.setWuxing(String.join(SEPARTOR, wuxingList));
*/
                lotteryTickets.add(lotteryTicket);
            }
            log.info("tbodyElement:{}", tbodyElement.html());
            log.info("lotteryTicketList:{}", JSON.toJSONString(lotteryTickets));
            if (CollectionUtils.isEmpty(lotteryTickets)) {
                return 0;
            }
            lotteryTickets.sort(new Comparator<LotteryTicket>() {
                @Override
                public int compare(LotteryTicket o1, LotteryTicket o2) {
                    return Integer.parseInt(o1.getNo()) - Integer.parseInt(o2.getNo());
                }
            });
            //lotteryTicketMapper.batchInsertLotteryTicket("fcap_lottery_ticket"+type,lotteryTickets);
            //lotteryTicketMapper.batchUpdateSerialNo("fcap_lottery_ticket"+type, type);
            log.info("==================================");


        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    @Transactional
    public void calculateRepeat(String sort, int type) throws Exception {
        List<LotteryTicket> list = lotteryTicketMapper.selectTicketList(sort, type, "fcap_lottery_ticket"+type);
        log.info("start:{}", JSON.toJSONString(list));
        if (list == null && list.size() == 0) {
            throw new BizException("00000001", "没有数据");
        }
        Map<Long, LotteryTicket> map = new HashMap<>();
        for (LotteryTicket lotteryTicket : list) {
            map.put(lotteryTicket.getId(), lotteryTicket);
        }
        LotteryTicket ticket = list.get(0);
        long currentId = ticket.getId();

        LotteryTicket maxTicket = list.get(list.size() - 1);
        long max = maxTicket.getId();

        for (int i = 1; i < 8; i++) {
            if ("desc".equals(sort)) {
                cal(map, currentId, i);
            } else {
                cal2(map, currentId, i, max);
            }
        }
        log.info("list:{}", JSON.toJSONString(list));
        lotteryTicketMapper.batchUpdateLotteryTicket(list, "fcap_lottery_ticket"+type);
    }

    private void cal(Map<Long, LotteryTicket> map, long currentId, int num) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        while (currentId > 0) {
            LotteryTicket current = map.get(currentId);
            String[] currentArr = current.getContent().split(SEPARTOR);
            List<String> currentContentList = new ArrayList<>();
            for (String a : currentArr) {
                currentContentList.add(a);
            }

            LotteryTicket next = map.get(currentId - num);
            if (next == null) {
                break;
            }
            String[] nextArrs = next.getContent().split(SEPARTOR);
            List<String> nextContents = new ArrayList<>();
            for (String aa : nextArrs) {
                nextContents.add(aa);
            }
            log.info("{} - contentList:{}", current.getNo(), JSON.toJSONString(currentContentList));
            log.info("{} - nextContents:{}", next.getNo(), JSON.toJSONString(nextContents));
            currentContentList.retainAll(nextContents);
            log.info("交集:{}", JSON.toJSONString(currentContentList));

            Method m = LotteryTicket.class.getMethod("setS" + num, Integer.class);
            if (CollectionUtils.isEmpty(currentContentList)) {
                m.invoke(current, 0);
            } else {
                m.invoke(current, 1);
            }
            log.info("{} - current:{}", current.getNo(), JSON.toJSONString(current));

            currentId = currentId - 1;
        }
    }

    private void cal2(Map<Long, LotteryTicket> map, long currentId, int num, long max) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        while (currentId <= max) {
            LotteryTicket current = map.get(currentId);
            String[] currentArr = current.getContent().split(SEPARTOR);
            List<String> currentContentList = new ArrayList<>();
            for (String a : currentArr) {
                currentContentList.add(a);
            }

            LotteryTicket next = map.get(currentId + num);
            if (next == null) {
                break;
            }
            String[] nextArrs = next.getContent().split(SEPARTOR);
            List<String> nextContents = new ArrayList<>();
            for (String aa : nextArrs) {
                nextContents.add(aa);
            }
            log.info("{} - contentList:{}", current.getNo(), JSON.toJSONString(currentContentList));
            log.info("{} - nextContents:{}", next.getNo(), JSON.toJSONString(nextContents));
            nextContents.retainAll(currentContentList);
            log.info("交集:{}", JSON.toJSONString(nextContents));

            Method m = LotteryTicket.class.getMethod("setS" + num, Integer.class);
            if (CollectionUtils.isEmpty(nextContents)) {
                m.invoke(next, 0);
            } else {
                m.invoke(next, 1);
            }
            log.info("{} - current:{}", current.getNo(), JSON.toJSONString(next));

            currentId = currentId + 1;
        }
    }




    public Pagination<LotteryTicketRes> getTicketListPage(LotteryTicketReq req) {

        String collectionName = "lotteryTicket"+req.getType();
        Query query = new Query();
        if(StringUtils.isNotBlank(req.getNo())){
            try{
                Long queryNo = Long.valueOf(req.getNo());
                query.addCriteria(Criteria.where("_id").is(queryNo));
            }catch (Exception e){
                String[] noArr = req.getNo().split(",");
                query.addCriteria(Criteria.where("content").all(noArr));
            }
        }
        long total = mongoTemplate.count(query, collectionName);
        log.info("getTicketListPage total:{}", total);
        Pagination<LotteryTicketRes> pagination = new Pagination<LotteryTicketRes>(req.getPageNo(), req.getPageSize(), Integer.parseInt(String.valueOf(total)));
        if (total <= 0) {
            pagination.setList(new ArrayList<LotteryTicketRes>());
            return pagination;
        }
        //排序 Sort.Order.desc("id")  Sort.Direction.DESC, "id")
        query.with(PageRequest.of(req.getPageNo()-1,
                    req.getPageSize(), Sort.by(Sort.Order.desc("id"))));
        query.fields().include("id","content","no");

        List<MongoLotteryTicket> ticketList = mongoTemplate.find(query, MongoLotteryTicket.class, collectionName);
        List<LotteryTicketRes> lotteryTicketResList = new ArrayList<>();
        for(MongoLotteryTicket ticket: ticketList){
            LotteryTicketRes lotteryTicketRes = new LotteryTicketRes();
            lotteryTicketRes.setId(ticket.getId());
            lotteryTicketRes.setSerialNo(ticket.getNo());
            lotteryTicketRes.setNo(String.valueOf(ticket.getNo()));
            lotteryTicketRes.setContent(String.join(",", ticket.getContent()));
            List<TicketContent> contentList = new ArrayList<>();
            List<String> contents =  ticket.getContent();
            for(int i = 0; i < contents.size(); i++){
                TicketContent ticketContent = new TicketContent();
                ticketContent.setContent(contents.get(i));
                if (i == 6) {
                    ticketContent.setColor("green");
                } else {
                    ticketContent.setColor("red");
                }
                contentList.add(ticketContent);
            }
            lotteryTicketRes.setContentList(contentList);

            lotteryTicketResList.add(lotteryTicketRes);
        }
        pagination.setList(lotteryTicketResList);
        /*List<LotteryTicketRes> resultList = lotteryTicketMapper.selectTickets(req);

        for (LotteryTicketRes lotteryTicketRes : resultList) {

            String[] content = lotteryTicketRes.getContent().split(SEPARTOR);

            // 组装颜色和数字
            List<TicketContent> contentList = new ArrayList<>();
            for (int i = 0; i < content.length; i++) {
                TicketContent ticketContent = new TicketContent();
                ticketContent.setContent(content[i]);
                if (i == 6) {
                    ticketContent.setColor("green");
                } else {
                    ticketContent.setColor("red");
                }

                contentList.add(ticketContent);
            }

            lotteryTicketRes.setContentList(contentList);
        }

        pagination.setList(resultList);*/

        return pagination;
    }


    @Transactional
    public void calculateNewDataRepeat(String sort, int num) throws Exception {
        List<LotteryTicket> list = lotteryTicketMapper.selectTicketListLimit(sort, num);
        log.info("start:{}", JSON.toJSONString(list));
        if (list == null && list.size() == 0) {
            throw new BizException("00000001", "没有数据");
        }
        Map<Long, LotteryTicket> map = new HashMap<>();
        for (LotteryTicket lotteryTicket : list) {
            map.put(lotteryTicket.getId(), lotteryTicket);
        }
        LotteryTicket ticket = list.get(0);
        long currentId = ticket.getId();

        LotteryTicket maxTicket = list.get(list.size() - 1);
        long max = maxTicket.getId();

        for (int i = 1; i < 8; i++) {
            if ("desc".equals(sort)) {
                cal(map, currentId, i);
            } else {
                cal2(map, currentId, i, max);
            }
        }
        log.info("list:{}", JSON.toJSONString(list));
        lotteryTicketMapper.batchUpdateLotteryTicket(list, "fcap_lottery_ticket");
    }

    public int insertLotteryTicket(LotteryTicketReq req) {
        long validNo = Long.valueOf(req.getNo());
        if(req.getSerialNo() <= 0 || validNo <= 0){
            throw new BizException("00000001", "序号和期数必须从1开始");
        }
        String collectionName = "lotteryTicket"+req.getType();
        MongoLotteryTicket lotteryTicket = new MongoLotteryTicket();
        lotteryTicket.setId(req.getSerialNo());
        lotteryTicket.setNo(Long.valueOf(req.getNo()));
        String[] contentArr = req.getContent().split(",");
        List<String> content = Arrays.asList(contentArr);
        lotteryTicket.setContent(content);
        lotteryTicket.setCreatedDate(new Date());
        lotteryTicket.setUpdatedDate(new Date());
//        List<AggregationOperation> aggregationOperationList = new ArrayList<>();
//        String NULL = null;
//        // id 最大最小值
//        aggregationOperationList.add(Aggregation.group("id").min("id").as("small").max("id").as("big"));
//        Aggregation aggregation = Aggregation.newAggregation(aggregationOperationList);
//
//        AggregationResults<NumberRes> aggregationResults = mongoTemplate.aggregate(aggregation, collectionName, NumberRes.class);
//
//        log.info("aggregationResults:{}", JSON.toJSONString(aggregationResults));


        Query query = new Query();
        query.with(Sort.by(Sort.Direction.ASC, "id"));
        query.fields().include("id").include("content");
        List<MongoLotteryTicket> list = mongoTemplate.find(query, MongoLotteryTicket.class, collectionName);
        log.info("list:{}", JSON.toJSONString(list));
        if(CollectionUtils.isEmpty(list) && lotteryTicket.getId() != 1){
            throw new BizException("00000001", "数据序号不连续");
        }
        // 添加第一条数据
        if(CollectionUtils.isEmpty(list) && lotteryTicket.getId() == 1){
            lotteryTicket.setResult(new ArrayList<Integer>());
            mongoTemplate.insert(lotteryTicket, collectionName);
           return 1;
        }
        long big = list.get(list.size()-1).getId();
        long small = list.get(0).getId();
        if(!CollectionUtils.isEmpty(list) && lotteryTicket.getId()<= big && big >= small){
            throw new BizException("00000001", "序号已存在");
        }
        if(list.size() != big || (lotteryTicket.getId()-1) != big){
            throw new BizException("00000001", "数据序号不连续，无法添加");
        }
        List<Integer> results = new ArrayList<>();
        for(MongoLotteryTicket ticket: list){
            List<String> contents = ticket.getContent();
            if(CollectionUtils.isEmpty(contents)){
                throw new BizException("00000001", "存在内容为空的数据，请删除!");
            }
            contents.retainAll(lotteryTicket.getContent());

            Integer a = contents.size()==0? 0:1;
            results.add(a);
        }
        log.info("results:{}", JSON.toJSONString(results));
        lotteryTicket.setResult(results);

        mongoTemplate.insert(lotteryTicket, collectionName);



        /*NumberRes numberRes = lotteryTicketMapper.getSubtractSerialNo(req.getType(), "fcap_lottery_ticket"+req.getType());
        if (numberRes == null || numberRes.getBig() == null
                || numberRes.getSmall() == null || numberRes.getSubtract() == null) {
            log.error("jiSuanRepeat numberRes is null, return...");
            return 0;
        }
        if (numberRes.getSubtract().longValue() <= 1) {
            log.error("jiSuanRepeat getSubtract is error, return...");
            return 0;
        }
        List<String> repeatList = lotteryTicketMapper.getRepeatSerialNo(req.getType(), "fcap_lottery_ticket"+req.getType());
        if (!CollectionUtils.isEmpty(repeatList)) {
            throw new BizException("00000001", "这些序号出现了重复" + String.join("，", repeatList) + "。请修改序号");
        }
        LotteryTicketReq queryReq = new LotteryTicketReq();
        queryReq.setType(req.getType());
        queryReq.setTableName("fcap_lottery_ticket"+req.getType());
        Integer count = lotteryTicketMapper.selectTicketsCount(queryReq);
        if (count.longValue() != numberRes.getSubtract().longValue()) {
            throw new BizException("00000001", "序号没有连续，请修改数据序号");
        }

        List<LotteryTicket> list = lotteryTicketMapper.selectTicketList("asc", req.getType(), "fcap_lottery_ticket"+req.getType());
        Map<Long, LotteryTicket> lotteryTicketMap = new HashMap<>();
        for (LotteryTicket lotteryTicket : list) {
            lotteryTicketMap.put(lotteryTicket.getSerialNo(), lotteryTicket);
        }
        Integer big = numberRes.getBig();
        Integer small = numberRes.getSmall();
        long startTime = System.currentTimeMillis();

        LotteryTicket currentObj = lotteryTicketMap.get(req.getSerialNo());
        String[] arr2 = currentObj.getContent().split(",");
        List<String> nextContents = new ArrayList<>();
        for (String aa : arr2) {
            nextContents.add(aa);
        }
        long preId = req.getSerialNo() - 1;
        List<LotteryTicket> tmpList = new ArrayList<>();
        while (preId >= 1) {
            LotteryTicket preObj = lotteryTicketMap.get(preId);
            String[] arr1 = preObj.getContent().split(",");
            List<String> contents = new ArrayList<>();
            for (String bb : arr1) {
                contents.add(bb);
            }
            contents.retainAll(nextContents);
            LotteryTicket tmp = new LotteryTicket();
            tmp.setSerialNo(currentObj.getSerialNo());
            tmp.setOtherSerialNo(preObj.getSerialNo());
            tmp.setType(currentObj.getType());
            if (CollectionUtils.isEmpty(contents)) {
                tmp.setResult(0);
            } else {
                tmp.setResult(1);
            }
            tmpList.add(tmp);

            preId = preId - 1;
        }
        batchInsert(tmpList, req.getType());*/

        return 1;
    }

    public int updateLotteryTicket(LotteryTicketReq req) {

        String collectionName = "lotteryTicket"+req.getType();
        Long id = req.getId();
        String[] contentArr = req.getContent().split(",");
        List<String> newContent = Arrays.asList(contentArr);
        // 要修改的那个数据
        Query updateQuery = new Query(Criteria.where("_id").is(id));
        Update update = new Update();
        update.set("content", newContent);
        update.set("updatedDate", new Date());

        if(id == 1){
            mongoTemplate.upsert(updateQuery, update, MongoLotteryTicket.class, collectionName);
            return 1;
        }

        Query query = new Query();
        query.with(Sort.by(Sort.Direction.ASC, "id"));
        query.fields().include("id").include("content").include("result");

        List<MongoLotteryTicket> ticketList = mongoTemplate.find(query, MongoLotteryTicket.class, collectionName);
        log.info("ticketList:{}", JSON.toJSONString(ticketList));
        if(CollectionUtils.isEmpty(ticketList)){
            throw new BizException("00000001", "数据不存在");
        }
        List<Integer> result = new ArrayList<>();
        for (MongoLotteryTicket mongoLotteryTicket: ticketList){
            List<String> contents = mongoLotteryTicket.getContent();
            List<String> tempList = new ArrayList<>(contents);
            if(mongoLotteryTicket.getId() < id){
                tempList.retainAll(newContent);
                Integer a = tempList.size()==0? 0:1;
                result.add(a);
            }else if(mongoLotteryTicket.getId() == id){
                update.set("result", result);
                mongoTemplate.upsert(updateQuery, update, MongoLotteryTicket.class, collectionName);
                result = null;
            }else{
                // 要【修改的那个数据】后面的数据，改它们的重复结果
                tempList.retainAll(newContent);
                Integer a = tempList.size()==0? 0:1;
                mongoLotteryTicket.getResult().set(Integer.parseInt(String.valueOf(id-1)), a);

                Query tempQuery = new Query(Criteria.where("_id").is(mongoLotteryTicket.getId()));
                Update tempUpdate = new Update();
                tempUpdate.set("result", mongoLotteryTicket.getResult());
                tempUpdate.set("updatedDate", new Date());
                mongoTemplate.upsert(tempQuery, tempUpdate, MongoLotteryTicket.class, collectionName);
            }
        }

        return 1;
    }

    public int delLotteryTicket(LotteryTicketReq req) {
//        req.setTableName("fcap_lottery_ticket"+req.getType());
//        req.setTableName2("fcap_lottery_ticket_result"+req.getType());
//        int rows = lotteryTicketMapper.delLotteryTicket(req);
//        if (rows > 0) {
//            Long id = lotteryTicketMapper.getMaxId(req.getTableName());
//            if (id != null) {
//
//                String sql = "alter sequence "+req.getTableName()+"_id_seq restart with " + (id + 1);
//                lotteryTicketMapper.restartSequence(sql);
//            }
//        }
        Query query = new Query(Criteria.where("_id").gte(req.getId()));
        String collectionName = "lotteryTicket"+req.getType();
        mongoTemplate.remove(query, collectionName);
        return 1;
    }

    public void jiSuanRepeat(String calculate, int type) {
        NumberRes numberRes = lotteryTicketMapper.getSubtractSerialNo(type, "fcap_lottery_ticket"+type);
        if (numberRes == null || numberRes.getBig() == null
                || numberRes.getSmall() == null || numberRes.getSubtract() == null) {
            log.error("jiSuanRepeat numberRes is null, return...");
            return;
        }
        if (numberRes.getSubtract().longValue() <= 1) {
            log.error("jiSuanRepeat getSubtract is error, return...");
            return;
        }
        List<String> repeatList = lotteryTicketMapper.getRepeatSerialNo(type, "fcap_lottery_ticket"+type);
        if (!CollectionUtils.isEmpty(repeatList)) {
            throw new BizException("00000001", "这些序号出现了重复" + String.join("，", repeatList) + "。请修改序号");
        }
        LotteryTicketReq queryReq = new LotteryTicketReq();
        queryReq.setType(type);
        queryReq.setTableName("fcap_lottery_ticket"+type);
        Integer count = lotteryTicketMapper.selectTicketsCount(queryReq);
        if (count.longValue() != numberRes.getSubtract().longValue()) {
            throw new BizException("00000001", "序号没有连续，请修改数据序号");
        }

        List<LotteryTicket> list = lotteryTicketMapper.selectTicketList("asc", type, "fcap_lottery_ticket"+type);
        Map<Long, LotteryTicket> map = new HashMap<>();
        for (LotteryTicket lotteryTicket : list) {
            map.put(lotteryTicket.getSerialNo(), lotteryTicket);
        }
        Integer big = numberRes.getBig();
        Integer small = numberRes.getSmall();
        long startTime = System.currentTimeMillis();
        //log.info("======开始计算重复:"+ startTime);
        /*long bigId = big;
        long currentId = small + 1;*/
        if ("1".equals(calculate)) {
            workStealingService.execute(new CalculateRepeatTask(big, big, lotteryTicketMapper, map, type));
        } else {
            for (int i = small + 1; i <= big; i++) {
                workStealingService.execute(new CalculateRepeatTask(i, big, lotteryTicketMapper, map, type));
            }
        }

        //log.info("======计算重复结束 cost:"+ (System.currentTimeMillis() - startTime)/1000 + "秒");
    }

    public void jsRepeat(int type, int small,  int big) {
        NumberRes numberRes = lotteryTicketMapper.getSubtractSerialNo(type, "fcap_lottery_ticket"+type);
        if (numberRes == null || numberRes.getBig() == null
                || numberRes.getSmall() == null || numberRes.getSubtract() == null) {
            log.error("jiSuanRepeat numberRes is null, return...");
            return;
        }
        if (numberRes.getSubtract().longValue() <= 1) {
            log.error("jiSuanRepeat getSubtract is error, return...");
            return;
        }
        List<String> repeatList = lotteryTicketMapper.getRepeatSerialNo(type, "fcap_lottery_ticket"+type);
        if (!CollectionUtils.isEmpty(repeatList)) {
            throw new BizException("00000001", "这些序号出现了重复" + String.join("，", repeatList) + "。请修改序号");
        }
        LotteryTicketReq queryReq = new LotteryTicketReq();
        queryReq.setType(type);
        queryReq.setTableName("fcap_lottery_ticket"+type);
        Integer count = lotteryTicketMapper.selectTicketsCount(queryReq);
        if (count.longValue() != numberRes.getSubtract().longValue()) {
            throw new BizException("00000001", "序号没有连续，请修改数据序号");
        }

        List<LotteryTicket> list = lotteryTicketMapper.selectTicketList("asc", type, "fcap_lottery_ticket"+type);
        Map<Long, LotteryTicket> map = new HashMap<>();
        for (LotteryTicket lotteryTicket : list) {
            map.put(lotteryTicket.getSerialNo(), lotteryTicket);
        }

        for (int i = small; i <= big; i++) {
            workStealingService.execute(new CalculateRepeatTask(i, big, lotteryTicketMapper, map, type));
        }
    }

    private void batchInsert(List<LotteryTicket> tmpList, int type) {
        // 批量插入
        if (!CollectionUtils.isEmpty(tmpList)) {
            List<LotteryTicket> newList = new ArrayList<>();
            for (int i = 0; i < tmpList.size(); i++) {
                newList.add(tmpList.get(i));
                // 每500条数据批量保存一次
                if (i != 0 && i % 500 == 0) {
                    lotteryTicketMapper.batchInsertLotteryTicketResult(tmpList, "fcap_lottery_ticket_result"+type);
                    newList.clear();
                }
            }

            // 最后一个批次数据
            if (newList.size() > 0) {
                lotteryTicketMapper.batchInsertLotteryTicketResult(tmpList, "fcap_lottery_ticket_result"+type);
            }
        }
    }

    static class CalculateRepeatTask implements Runnable {
        private long id; // serialNo
        private long maxId; // serialNo
        private LotteryTicketMapper lotteryTicketMapper;
        private Map<Long, LotteryTicket> lotteryTicketMap;
        private int type;

        public CalculateRepeatTask(long id, long maxId, LotteryTicketMapper lotteryTicketMapper, Map<Long, LotteryTicket> lotteryTicketMap, int type) {
            this.id = id;
            this.lotteryTicketMapper = lotteryTicketMapper;
            this.lotteryTicketMap = lotteryTicketMap;
            this.maxId = maxId;
            this.type= type;
        }

        @Override
        @Transactional
        public void run() {
            LotteryTicket currentObj = lotteryTicketMap.get(id);
            String[] arr2 = currentObj.getContent().split(",");
            List<String> nextContents = new ArrayList<>();
            for (String aa : arr2) {
                nextContents.add(aa);
            }
            long preId = id - 1;
            List<LotteryTicket> tmpList = new ArrayList<>();
            while (preId >= 1) {
                LotteryTicket preObj = lotteryTicketMap.get(preId);
                String[] arr1 = preObj.getContent().split(",");
                List<String> contents = new ArrayList<>();
                for (String bb : arr1) {
                    contents.add(bb);
                }
                contents.retainAll(nextContents);
                LotteryTicket tmp = new LotteryTicket();
                tmp.setSerialNo(currentObj.getSerialNo());
                tmp.setOtherSerialNo(preObj.getSerialNo());
                tmp.setType(currentObj.getType());
                if (CollectionUtils.isEmpty(contents)) {
                    tmp.setResult(0);
                } else {
                    tmp.setResult(1);
                }
                tmpList.add(tmp);

                preId = preId - 1;
            }
            batchInsert(tmpList, type);

/*            if(id == maxId){
                lotteryTicketMapper.deleteLotteryTicketResultTemp();

                lotteryTicketMapper.insertLotteryTicketResultTemp(maxId, 1);
                lotteryTicketMapper.insertLotteryTicketResultTemp(maxId, 2);
                lotteryTicketMapper.insertLotteryTicketResultTemp(maxId, 3);
                lotteryTicketMapper.insertLotteryTicketResultTemp(maxId, 4);
                lotteryTicketMapper.insertLotteryTicketResultTemp(maxId, 5);
                lotteryTicketMapper.insertLotteryTicketResultTemp(maxId, 6);
                lotteryTicketMapper.insertLotteryTicketResultTemp(maxId, 7);
            }*/
        }

        private void batchInsert(List<LotteryTicket> tmpList, int type) {
            // 批量插入
            if (!CollectionUtils.isEmpty(tmpList)) {
                List<LotteryTicket> newList = new ArrayList<>();
                for (int i = 0; i < tmpList.size(); i++) {
                    newList.add(tmpList.get(i));
                    // 每500条数据批量保存一次
                    if (i != 0 && i % 500 == 0) {
                        lotteryTicketMapper.batchInsertLotteryTicketResult(tmpList, "fcap_lottery_ticket_result"+type);
                        newList.clear();
                    }
                }

                // 最后一个批次数据
                if (newList.size() > 0) {
                    lotteryTicketMapper.batchInsertLotteryTicketResult(tmpList, "fcap_lottery_ticket_result"+type);
                }
            }
        }

    }


    static class GetWinLotteryTask implements Runnable {
        private int num; //隔几组算重复
        private long maxId; // 序号，最新一期的id
        private int repeat; // 重复次数大于多少，才查出来
        private LotteryTicketMapper lotteryTicketMapper;
        private List<LotteryTicketRes> lotteryTicketList;
        private CountDownLatch countDownLatch;
        private int type;
        public GetWinLotteryTask(int num, long maxId, int repeat,LotteryTicketMapper lotteryTicketMapper, List<LotteryTicketRes> lotteryTicketList, CountDownLatch countDownLatch, int type) {
            this.num = num;
            this.maxId = maxId;
            this.repeat = repeat;
            this.lotteryTicketMapper = lotteryTicketMapper;
            this.lotteryTicketList = lotteryTicketList;
            this.countDownLatch = countDownLatch;
            this.type = type;
        }
        @Override
        public void run() {
           List<LotteryTicketRes> list =  lotteryTicketMapper.selectWinRepeatTicketList(maxId,"fcap_lottery_ticket_result"+type, num, type);
           if(CollectionUtils.isEmpty(list) || list.size()< repeat){
               countDownLatch.countDown();
               return;
           }
           boolean flag = false;
           for(int i = 0; i < list.size(); i++){
                if(list.get(i).getResult() == 0){
                    flag = true;
                    if((i) >= repeat){
                        long otherSerialNo = list.get(0).getOtherSerialNo();
                        otherSerialNo = otherSerialNo + 1;
                        LotteryTicketRes ticketRes = lotteryTicketMapper.selectTicketByNo(otherSerialNo, type, "fcap_lottery_ticket"+type);
                        ticketRes.setRepeat(Long.valueOf(i));
                        ticketRes.setNum(num);
                        lotteryTicketList.add(ticketRes);
                    }
                    break;
               }
           }
           if(!flag){
               if(list.size() >= repeat){
                   long serialNo = list.get(0).getSerialNo();
                   //otherSerialNo = otherSerialNo + 1;
                   LotteryTicketRes ticketRes = lotteryTicketMapper.selectTicketByNo(serialNo, type, "fcap_lottery_ticket"+type);
                   if(ticketRes != null){
                       ticketRes.setRepeat(Long.valueOf(list.size()-1));
                       ticketRes.setNum(num);
                       lotteryTicketList.add(ticketRes);
                   }
               }
           }
           countDownLatch.countDown();

        }
    }



    @Override
    public List<LotteryTicketRes> getBuyTicketList(LotteryTicketReq req) {
        //Integer maxSerialNo = lotteryTicketMapper.getMaxSerialNo(req.getType(), "fcap_lottery_ticket"+req.getType());
        String collectionName = "lotteryTicket"+req.getType();
        Query query = new Query();
        query.with(Sort.by(Sort.Order.asc("id")));
        query.fields().include("id","no", "content","result");
        List<MongoLotteryTicket> ticketList = mongoTemplate.find(query, MongoLotteryTicket.class, collectionName);
        if(CollectionUtils.isEmpty(ticketList)){
            log.info("getBuyTicketList Ticket is empty");
            return new ArrayList<>();
        }
        MongoLotteryTicket maxTicket = ticketList.get(ticketList.size()-1);
        if(maxTicket == null || maxTicket.getId() == null){
            log.info("getBuyTicketList maxTicket is null");
            return new ArrayList<>();
        }
        Integer maxSerialNo = Integer.parseInt(maxTicket.getId().toString());
        if(maxSerialNo <= 3){
            return new ArrayList<>();
        }
        int num = 1;
        /*if(req.getType()==2){
            num = 280;
        }
        if(req.getType()==3 || req.getType()==4){*/
        num = maxSerialNo-2;

        //}

        ForkJoinPool fjp = new ForkJoinPool(); // 最大并发数4
        GetBuyTicketTask task = new GetBuyTicketTask(ticketList, 1, num);

        long startTime = System.currentTimeMillis();
        List<LotteryTicketRes> lotteryTicketList = fjp.invoke(task);
        long endTime = System.currentTimeMillis();
        log.info("Fork join result: " + JSON.toJSONString(lotteryTicketList) + " in " + (endTime - startTime) + " ms.");

        if(!CollectionUtils.isEmpty(lotteryTicketList)){
            lotteryTicketList.sort(new Comparator<LotteryTicketRes>() {
                @Override
                public int compare(LotteryTicketRes o1, LotteryTicketRes o2) {
                    return Integer.parseInt(o2.getRepeat()-o1.getRepeat() + "");
                }
            });
        }

        return lotteryTicketList;
    }




}